package com.mindata.blockchain.socket.common.queue;

import com.mindata.blockchain.ApplicationContextProvider;
import com.mindata.blockchain.block.block.BaseBlock;
import com.mindata.blockchain.block.block.Block;
import com.mindata.blockchain.block.block.DGLBlock;
import com.mindata.blockchain.common.Commonvalue;
import com.mindata.blockchain.common.timer.TimerManager;
import com.mindata.blockchain.core.event.AddBlockEvent;
import com.mindata.blockchain.core.event.DGLAddBlocksEvent;
import com.mindata.blockchain.core.manager.DbBlockManager;
import com.mindata.blockchain.socket.body.rpc.RpcBlockBody;
import com.mindata.blockchain.socket.body.rpc.RpcDGLBlockBody;
import com.mindata.blockchain.socket.client.PacketSender;
import com.mindata.blockchain.socket.common.Const;
import com.mindata.blockchain.socket.packet.BlockPacket;
import com.mindata.blockchain.socket.packet.PacketBuilder;
import com.mindata.blockchain.socket.packet.PacketType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class IntroAddBlockQueue {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 存储所有的hash的TX集合
     */
    private boolean isdealed = false;
    public int maxinner = 0;
    public int maxintro = 0;
    public ConcurrentHashMap<Integer, Block> blockConcurrentHashMap = new ConcurrentHashMap<>();
    public ConcurrentHashMap<Integer, DGLBlock> dglBlockConcurrentHashMap = new ConcurrentHashMap<>();
    /**
     * 存储本节点已签名状态的hash的集合，即本节点已对外广播的交易消息
     */
    public ConcurrentHashMap<Integer, Boolean> blockStateConcurrentHashMap = new ConcurrentHashMap<>();
    @Resource
    private DbBlockManager dbBlockManager;
    @Resource
    PacketSender packetSender;
    @Resource
    Commonvalue commonvalue;

    public void push(BaseBlock block) {
        if (block instanceof Block) {
            push((Block) block);
        } else {
            push((DGLBlock) block);
        }
    }

    public void push(Block block) {
        Integer number = block.getBlockHeader().getNumber();
        //避免收到重复消息
        if (blockConcurrentHashMap.get(number) != null) {
            return;
        }
        //存入Pre集合中
        synchronized (Const.inner_Lock) {
            maxinner = maxinner > number ? maxinner : number;
        }
        blockConcurrentHashMap.put(number, block);
        deal();
    }

    public void push(DGLBlock block) {
        Integer number = block.getBlockList().get(0).getBlockHeader().getNumber();
        //避免收到重复消息
        if (dglBlockConcurrentHashMap.get(number) != null) {
            return;
        }
        //存入Pre集合中
        synchronized (Const.intro_Lock) {
            maxintro = maxintro > number ? maxintro : number;
        }
        dglBlockConcurrentHashMap.put(number, block);
        deal();
    }

    public void deal() {
        int number = dbBlockManager.getLastDGLBlockNumber() + 1;
        if (!blockStateConcurrentHashMap.containsKey(number) && blockConcurrentHashMap.containsKey(number) && dglBlockConcurrentHashMap.containsKey(number)) {
            if (number % commonvalue.getGroupsize() == commonvalue.getNodeIndex())
                ApplicationContextProvider.publishEvent(new AddBlockEvent(blockConcurrentHashMap.get(number)));
            ApplicationContextProvider.publishEvent(new DGLAddBlocksEvent(dglBlockConcurrentHashMap.get(number)));
            blockStateConcurrentHashMap.put(number, true);
        }
    }

    @Order(4)
    @EventListener(DGLAddBlocksEvent.class)
    public void publishDGLBlock(DGLAddBlocksEvent dglAddBlocksEvent) {
        DGLBlock dglblock = (DGLBlock) dglAddBlocksEvent.getSource();
        BlockPacket packet = new PacketBuilder<RpcDGLBlockBody>()
                .setType(PacketType.DGL_BLOCK_UPDATE)
                .setBody(new RpcDGLBlockBody(dglblock)).build();
        packetSender.sendGroup(packet);

    }
}
